package com.tiancheng.trade.commom.core.utils;

import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.time.temporal.Temporal;
import java.util.*;

/**
 * 日期时间工具类
 *
 * @author kellen
 * @date 2019/3/12
 */
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public final class DateTimeUtil {



    private static final String utc_pattern = "yyyy-MM-dd'T'HH:mm:ss'Z'";
    private static final String gmt_pattern = "yyyy-MM-dd'T'HH:mm:ssX";
    public static final String bj_pattern = "yyyy-MM-dd HH:mm:ss";
    private static final String pst_pattern = "HH:mm:ss MMM dd, yyyy";

    /**
     * yyyyMMdd
     */
    public static final String yyyyMMdd="yyyyMMdd";
    /**
     * yyyy-MM-dd
     */
    public static final String YYYYMMDD_INTERVAL="yyyy-MM-dd";

    public static final String BEIJING = "Asia/Shanghai";  //也可以使用"+8" 北京在东8区

    public static final String US_PST = "America/Los_Angeles";  //也可以使用"-8" 太平洋标准时区

    public static final String  fmt_yyyyMMddHHmmss="yyyyMMddHHmmss";

    /** String to LocalDateTime
     *
     * @param dateTime
     * @param pattern
     * @return */
    public static LocalDateTime format(String dateTime, String pattern) {

        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        return LocalDateTime.parse(dateTime, df);
    }

    /** String to LocalDate
     *
     * @param dateTime
     * @param pattern
     * @return */
    public static LocalDate formatDate(String dateTime, String pattern) {

        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        return LocalDate.parse(dateTime, df);
    }

    /** String to LocalTime
     *
     * @param dateTime
     * @param pattern
     * @return */
    public static LocalTime formatTime(String dateTime, String pattern) {

        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        return LocalTime.parse(dateTime, df);
    }

    /**
     * dateTime format to string
     * @param dateTime
     * @param pattern
     * @return
     */
    public static String format(Temporal dateTime, String pattern) {
        DateTimeFormatter df = DateTimeFormatter.ofPattern(pattern);
        return df.format(dateTime);
    }

    /**
     * timestamp to LocalDateTime
     * @param timestamp
     * @return
     */

    public static LocalDateTime timestamp2Datetime(Long timestamp){
        if(timestamp==null){
            return null;
        }
        Instant instant = Instant.ofEpochMilli(timestamp);
        return LocalDateTime.ofInstant(instant, ZoneId.systemDefault());
    }

    /**
     * String to LocalDate
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDate}
     */
    public static LocalDate string2LocalDate(String dateTime, String pattern) {
        return LocalDate.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }


    /**
     * String to LocalDateTime
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime string2LocalDateTime(String dateTime, String pattern) {
        return LocalDateTime.parse(dateTime, DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * Date to LocalDate
     *
     * @param date {@link Date}
     * @return {@link LocalDate}
     */
    public static LocalDate date2LocalDate(Date date) {
        return date.toInstant().atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Date to LocalDateTime
     *
     * @param date {@link Date}
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime date2LocalDateTime(Date date) {
        return LocalDateTime.ofInstant(date.toInstant(), ZoneId.systemDefault());
    }

    /**
     * Temporal format to String
     *
     * @param dateTime {@link Temporal}
     * @param pattern  {@link String}
     * @return {@link String}
     */
    public static String temporalFormat2String(Temporal dateTime, String pattern) {
        return DateTimeFormatter.ofPattern(pattern).format(dateTime);
    }

    /**
     * Timestamp to LocalDate
     *
     * @param timestamp long时间戳
     * @return {@link LocalDate}
     */
    public static LocalDate timestamp2LocalDate(long timestamp) {
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDate();
    }

    /**
     * Timestamp to LocalDateTime
     *
     * @param timestamp long时间戳
     * @return {@link LocalDateTime}
     */
    public static LocalDateTime timestamp2LocalDateTime(long timestamp) {
        return Instant.ofEpochMilli(timestamp).atZone(ZoneId.systemDefault()).toLocalDateTime();
    }

    /**
     * LocalDateTime to string
     *
     * @param dateTime {@link String}
     * @param pattern  {@link String}
     * @return {@link LocalDate}
     */
    public static String formatter(LocalDateTime dateTime, String pattern) {
        return dateTime.format(DateTimeFormatter.ofPattern(pattern));
    }

    /**
     * 获取当天日期 yyyyMMdd
     *
     * @return
     */
    public static String getCurrentDay() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd"));
    }

    /**
     * 获取当前时间 HHmmss
     *
     * @return
     */
    public static String getCurrentTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern("HHmmss"));
    }

    /**
     * 获取当前时间 HHmmss
     *
     * @return
     */
    public static String getCurrentDateTime() {
        return LocalDateTime.now().format(DateTimeFormatter.ofPattern(fmt_yyyyMMddHHmmss));
    }

    /**
     * UTC时间转北京时间
     *
     * @param utcTime 国际时间  时间为： 2021-10-27T06:23:09Z   格式为: yyyy-MM-dd'T'HH:mm:ss'Z'
     * @return
     */
    public static LocalDateTime Utc2Beijing(String utcTime) throws ParseException {
        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(utc_pattern);
        srcdate = sdf.parse(utcTime);
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(srcdate);
        calendar.set(Calendar.HOUR, calendar.get(Calendar.HOUR) + 8);

        //SimpleDateFormat simpleDateFormat = new SimpleDateFormat(bj_pattern);
        Date tardate = calendar.getTime();
        return date2LocalDateTime(tardate);
    }

    /**
     * GMT-08:00 时区转为北京时间
     *
     * @param gmtTime 时间为： 2021-10-27T00:33:23-07:00  格式为：yyyy-MM-dd'T'HH:mm:ssX
     * @return
     * @throws ParseException
     */
    public static LocalDateTime GMT2Beijing(String gmtTime) throws ParseException {
        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(gmt_pattern);
        srcdate = sdf.parse(gmtTime);
        return date2LocalDateTime(srcdate);
    }

    /**
     * @param srcTime 23:23:09 Oct 26, 2021 PDT   太平洋夏季时间+15h=北京时间
     *                23:23:09 Nov 26, 2021 PST   太平洋冬季时间+16h=北京时间
     *                太平洋夏季时间从每年3月的第二个星期日到11月的第一个星期日期间和北京时间差15小时，其余月份和北京时间差16小时
     */
    public static LocalDateTime PDTorPST2Beijing(String srcTime) throws ParseException {
        String newSrcTime = "";
        if (srcTime.endsWith("PDT")) {
            newSrcTime = srcTime.substring(0, srcTime.indexOf("PDT")).trim();
        }
        if (srcTime.endsWith("PST")) {
            newSrcTime = srcTime.substring(0, srcTime.indexOf("PST")).trim();
        }

        Date srcdate = null;
        SimpleDateFormat sdf = new SimpleDateFormat(pst_pattern, Locale.US);
        srcdate = sdf.parse(newSrcTime);
        SimpleDateFormat sdf2 = new SimpleDateFormat(bj_pattern);
        System.out.println(date2LocalDateTime(srcdate));
        System.out.println(sdf2.format(srcdate));

        Date target = convertTimezone(srcdate, US_PST, BEIJING);
        long sub = target.getTime() - srcdate.getTime();
        System.out.println("北京时间与洛杉矶时间相差时间: " + sub / (60 * 60 * 1000) + " 小时");
        return date2LocalDateTime(target);
    }

    public static Date convertTimezone(Date sourceDate, String sourceZoneId, String targetZoneId) {
        TimeZone sourceTimeZone = TimeZone.getTimeZone(sourceZoneId);
        TimeZone targetTimeZone = TimeZone.getTimeZone(targetZoneId);
        return convertTimezone(sourceDate, sourceTimeZone, targetTimeZone);
    }

    /**
     * 将sourceDate转换成指定时区的时间
     *
     * @param sourceDate
     * @param sourceTimezone sourceDate所在的时区
     * @param targetTimezone 转化成目标时间所在的时区
     * @return
     */
    public static Date convertTimezone(Date sourceDate, TimeZone sourceTimezone, TimeZone targetTimezone) {

        Calendar calendar = Calendar.getInstance();// date.getTime() 为时间戳, 为格林尼治到系统现在的时间差,世界各个地方获取的时间戳是一样的,       // 格式化输出时,因为设置了不同的时区,所以输出不一样
        long sourceTime = sourceDate.getTime();

        calendar.setTimeZone(sourceTimezone);
        calendar.setTimeInMillis(sourceTime);// 设置之后,calendar会计算各种filed对应的值,并保存

        int targetDaylightOffset = calendar.get(Calendar.DST_OFFSET); // 夏令时

        //获取源时区的到UTC的时区差
        int sourceZoneOffset = calendar.get(Calendar.ZONE_OFFSET);

        calendar.setTimeZone(targetTimezone);
        calendar.setTimeInMillis(sourceTime);

        int targetZoneOffset = calendar.get(Calendar.ZONE_OFFSET);

        long targetTime = sourceTime + targetZoneOffset - sourceZoneOffset - targetDaylightOffset;
        return new Date(targetTime);

    }


    public static Date LocalDateTimeToDate(LocalDateTime localDateTime) {
        ZoneId zone = ZoneId.systemDefault();
        Instant instant = localDateTime.atZone(zone).toInstant();
        return Date.from(instant);
    }

    public static LocalDateTime DateToLocalDateTime(Date date) {
        Instant instant = date.toInstant();
        ZoneId zoneId = ZoneId.systemDefault();
        return instant.atZone(zoneId).toLocalDateTime();
    }

    public static LocalDateTime getLocalDateTime(Date date, int count) {
        Calendar calendar = new GregorianCalendar();
        calendar.setTime(date);
        calendar.add(calendar.DATE, count); //把日期往后增加,整数  往后推,负数往前移动
        date = calendar.getTime();
        return DateToLocalDateTime(date);
    }

    public static int JudgeDatesValue(Date date1, Date date2) throws ParseException {
        SimpleDateFormat sdf = new SimpleDateFormat("yyyy-MM-dd");
        return sdf.parse(sdf.format(date1)).compareTo(sdf.parse(sdf.format(date2)));
    }

    /**
     * 获取指定月第几天的日期
     *
     * @return
     */
    public static Date getNextMonthDay(Date date, int monthInt, int dayInt) {
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date);
        calendar.set(Calendar.DAY_OF_MONTH, dayInt);
        calendar.add(Calendar.MONTH, monthInt);
        return calendar.getTime();
    }

    public static int getYearMonth(Date dt) {//传入日期
        Calendar cal = Calendar.getInstance();
        cal.setTime(dt);//设置时间来
        int year = cal.get(Calendar.YEAR);//获取年份
        int month = cal.get(Calendar.MONTH);//获取月份
        return year * 100 + month;//返回年份乘以源100加上月份的值，因为月份最多2位数，所以年份乘以100可以获取一个唯一的年月数值
    }

    public static String getSystemDate(String format) {//获取当前系统时间
        return new SimpleDateFormat(format).format(new Date());
    }
}
